/*-*-C-*-
 *
 * Code to handle input focus, new-style
 */

#include "resed.h"

#include "swicall.h"
#include "wimp.h"

#include "focus.h"


static int focuswindow = -1;          /* Window with the selection; -1 if we don't own it */
static FocusCallback callback = NULL; /* Called when focus changes */
static void *closure = NULL;          /* Passed to callback */
static int mytaskid = 0;

/*
 * gain focus in the given window.  If another of our windows currently has it
 * ask inform it that it has been taken away.  If we don't have it, then
 * broadcast the fact to the world at large.
 */

error * focus_claim (int window, FocusCallback cb, void *cls)
{
    if (window == focuswindow)        /* it's already there */
    {
        return NULL;
    }
    else if (focuswindow != -1)       /* it's in another of our windows */
    {
        if (callback)
        {
            int oldfocuswindow = focuswindow;
            focuswindow = -1;
            (*callback) (FocusLost, oldfocuswindow, closure);
        }
    }
    else                              /* it's elsewhere */
    {
        MessageClaimEntityRec claim;
        claim.header.size = sizeof(claim);
        claim.header.yourref = 0;
        claim.header.messageid = MESSAGE_CLAIM_ENTITY;
        claim.flags = BIT(0) | BIT(1);
        ER ( swi (Wimp_SendMessage,  R0, EV_USER_MESSAGE,  R1, &claim,  R2, 0,  END) );
        mytaskid = claim.header.taskhandle;
    }
    focuswindow = window;
    callback = cb;
    closure = cls;
    if (callback)
    {
        (*callback) (FocusGained, focuswindow, closure);
    }
    return NULL;
}


/*
 * The application should call this when it is deleting a window
 * that might have the focus.  It just resets the idea of where
 * the current focus is.  Does not call the callback.
 */

error * focus_giveup (int window)
{
    if (window == focuswindow)
    {
        focuswindow = -1;
        callback = NULL;
        closure = NULL;
    }
    return NULL;
}


/*
 * Inform caller of the current focus window, or -1 if it is
 * believed to be elsewhere.
 */

int focus_current ()
{
    return focuswindow;
}


/*
 * Call this on receipt of claim messages.  We ignore all
 * claim messages that originated from ourselves.
 */

error * focus_message_claim_entity (MessageClaimEntityPtr claim)
{
    if (claim->flags & (BIT(0) | BIT(1)) == 0)
        return NULL;
    
    if (claim->header.taskhandle == mytaskid)
        return NULL;
    
    if (focuswindow != -1)
    {
        if (callback)
        {
            int oldfocuswindow = focuswindow;
            focuswindow = -1;
            (*callback) (FocusLost, oldfocuswindow, closure);
        }
        focuswindow = -1;
        callback = NULL;
        closure = NULL;
    }
    return NULL;
}
